package draw

import (
	"math"
)

// line 画线
func line(
	x1, y1 int,
	x2, y2 int,
	call APICall,
) {
	var dx, dy, e, slope int
	// Because drawing p1 -> p2 is equivalent to draw p2 -> p1,
	// I sort points in x-axis order to handle only half of possible cases.
	if x1 > x2 {
		x1, y1, x2, y2 = x2, y2, x1, y1
	}
	dx, dy = x2-x1, y2-y1
	// Because point is x-axis ordered, dx cannot be negative
	if dy < 0 {
		dy = -dy
	}
	switch {
	// Is line a point ?
	case x1 == x2 && y1 == y2:
		call(x1, y1)
	// Is line an horizontal ?
	case y1 == y2:
		for ; dx != 0; dx-- {
			call(x1, y1)
			x1++
		}
		call(x1, y1)
	// Is line a vertical ?
	case x1 == x2:
		if y1 > y2 {
			y1, y2 = y2, y1
		}
		for ; dy != 0; dy-- {
			call(x1, y1)
			y1++
		}
		call(x1, y1)
	// Is line a diagonal ?
	case dx == dy:
		if y1 < y2 {
			for ; dx != 0; dx-- {
				call(x1, y1)
				x1++
				y1++
			}
		} else {
			for ; dx != 0; dx-- {
				call(x1, y1)
				x1++
				y1--
			}
		}
		call(x1, y1)
	// wider than high ?
	case dx > dy:
		if y1 < y2 {
			// BresenhamDxXRYD(img, x1, y1, x2, y2)
			dy, e, slope = 2*dy, dx, 2*dx
			for ; dx != 0; dx-- {
				call(x1, y1)
				x1++
				e -= dy
				if e < 0 {
					y1++
					e += slope
				}
			}
		} else {
			// BresenhamDxXRYU(img, x1, y1, x2, y2)
			dy, e, slope = 2*dy, dx, 2*dx
			for ; dx != 0; dx-- {
				call(x1, y1)
				x1++
				e -= dy
				if e < 0 {
					y1--
					e += slope
				}
			}
		}
		call(x2, y2)
	// higher than wide.
	default:
		if y1 < y2 {
			// BresenhamDyXRYD(img, x1, y1, x2, y2)
			dx, e, slope = 2*dx, dy, 2*dy
			for ; dy != 0; dy-- {
				call(x1, y1)
				y1++
				e -= dx
				if e < 0 {
					x1++
					e += slope
				}
			}
		} else {
			// BresenhamDyXRYU(img, x1, y1, x2, y2)
			dx, e, slope = 2*dx, dy, 2*dy
			for ; dy != 0; dy-- {
				call(x1, y1)
				y1--
				e -= dx
				if e < 0 {
					x1++
					e += slope
				}
			}
		}
		call(x2, y2)
	}
}

// circle 画圆
func circle(xc, yc, r int, call APICall) {
	for d, x, y := 3-2*r, 0, r; x <= y; x++ {
		call(xc+x, yc+y)
		call(xc-x, yc+y)
		call(xc+x, yc-y)
		call(xc-x, yc-y)
		call(xc+y, yc+x)
		call(xc-y, yc+x)
		call(xc+y, yc-x)
		call(xc-y, yc-x)
		if d < 0 {
			d = d + 4*x + 6
		} else {
			d = d + 4*(x-y) + 10
			y--
		}
	}
}

// bezier 贝塞尔公式调用
func bezier(bezier []APISpot, t float64, call APICall) {
	x, y := float64(0.0), float64(0.0)
	n := len(bezier) - 1
	for i := 0; i <= n; i++ {
		temp := combinate(n, i) * math.Pow(float64(t), float64(i)) * math.Pow(float64(1-t), float64(n-i))
		x += temp * float64(bezier[i].X)
		y += temp * float64(bezier[i].Y)
	}
	call(int(x), int(y))
}
